//bange_layerobject.cpp
//Copyright (C) 2010-2011 Oscar (.teri) Triano

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <bange_layerobject.hpp>
#include <bange_simplestring.hpp>
#include <bange_simplesprite.hpp>
#include <bange_sprite.hpp>

void bange::layerobject::RegisterVM(lua_State *vm){
	luaL_Reg method[] = {
	{"AddSimpleString", bangelayerobject_AddSimpleString},
	{"AddSimpleSprite", bangelayerobject_AddSimpleSprite},
	{"AddSprite", bangelayerobject_AddSprite},
	{NULL, NULL}};
	luaL_newmetatable(vm, "bange::layerobject_method");
	luaL_register(vm, NULL, method);
	lua_pop(vm, 1);
}

bange::layerobject::layerobject(cpSpace *space, lua_State *vm): bange::layer(space, vm){
}

bool bange::layerobject::Index(lua_State *vm){
	//layerobject, key
	if(this->bange::layer::Index(vm)){
		return true;}
	lua_getfield(vm, LUA_REGISTRYINDEX, "bange::layerobject_method");
	lua_getfield(vm, -1, lua_tostring(vm, 2));
	return true;
}

void bange::layerobject::ManageEvent(int indexlayer, int indexevent, sf::Event &event, lua_State *vm){
	list<bange::object *>::iterator aobject;
	int parent = LUA_REFNIL, indexobject = 0;
	for (aobject = this->objects.begin(); aobject != this->objects.end(); aobject++){
		lua_pushvalue(vm, indexlayer);
		parent = luaL_ref(vm, LUA_REGISTRYINDEX);
		bange::BuildProxy(parent, static_cast<bange::base *>(*aobject), vm);
		indexobject = lua_gettop(vm);
		(*aobject)->ExecuteEvents(indexobject, indexevent, event, vm);
		lua_pop(vm, 1);//object proxy
	}
}

void bange::layerobject::Process(int indexlayer, float frametime, lua_State *vm){
	list<bange::object *>::iterator aobject;
	int parent = LUA_REFNIL, indexobject = 0;
	aobject = this->objects.begin();
	while(aobject != this->objects.end()){
		if ((*aobject)->deleted == true){
			delete *aobject;
			aobject = this->objects.erase(aobject);
			continue;}
		lua_pushvalue(vm, indexlayer);
		parent = luaL_ref(vm, LUA_REGISTRYINDEX);
		bange::BuildProxy(parent, static_cast<bange::base *>(*aobject), vm);
		indexobject = lua_gettop(vm);
		(*aobject)->ExecuteFunctions(indexobject, vm);
		(*aobject)->ExecuteScheduleFunctions(indexobject, frametime, vm);
		(*aobject)->Process(frametime);
		lua_pop(vm, 1);//object proxy
		aobject++;
	}
	//cout << objects.size() << endl;
}

void bange::layerobject::Draw(sf::RenderWindow *renderwindow, sf::View &currentview){
	list<bange::object *>::iterator aobject;
	for (aobject = this->objects.begin(); aobject != this->objects.end(); aobject++){
		if ((*aobject)->visible){
			renderwindow->Draw(*(*aobject)->drawable);}
	}
	//renderwindow->Draw(*((dynamic_cast<bange::simplestring *>(this->lastobject))->drawable));
}

inline void bange::layerobject::AddObject(bange::object *aobject){
	this->objects.push_front(aobject);
}

void bange::layerobject::CleanVM(lua_State *vm){
	this->bange::layer::CleanVM(vm);
	list<bange::object *>::iterator aobject;
	for (aobject = this->objects.begin(); aobject != this->objects.end(); aobject++){
		(*aobject)->CleanVM(vm);
	}

}

bange::layerobject::~layerobject(){
	cout << "bange::layerobject destructor for:" << this << endl;
	list<bange::object *>::iterator aobject;
	for (aobject = this->objects.begin(); aobject != this->objects.end(); aobject++){
		delete *aobject;
	}
	this->objects.clear();
}

static int bangelayerobject_AddSimpleString(lua_State *vm){
	//layerobject, (string)
	bange::layerobject *layerobject = static_cast<bange::layerobject *>(bange::base::GetBaseFromProxy(1, vm));
	bange::simplestring *string = NULL;
	if (lua_isstring(vm, 2)){
		string = new bange::simplestring(lua_tostring(vm, 2), vm);}
	else{
		string = new bange::simplestring(vm);}
	layerobject->AddObject(static_cast<bange::object *>(string));
	lua_pushvalue(vm, 1);
	int parent = luaL_ref(vm, LUA_REGISTRYINDEX);
	bange::BuildProxy(parent, static_cast<bange::base *>(string), vm);
	return 1;
}

static int bangelayerobject_AddSimpleSprite(lua_State *vm){
	//layerobject
	bange::layerobject *layerobject = static_cast<bange::layerobject *>(bange::base::GetBaseFromProxy(1, vm));
	bange::simplesprite *sprite;
	sprite = new bange::simplesprite(vm);
	layerobject->AddObject(static_cast<bange::object *>(sprite));
	lua_pushvalue(vm, 1);
	int parent = luaL_ref(vm, LUA_REGISTRYINDEX);
	bange::BuildProxy(parent, static_cast<bange::base *>(sprite), vm);
	return 1;
}

static int bangelayerobject_AddSprite(lua_State *vm){
	//layerobject
	bange::layerobject *layerobject = static_cast<bange::layerobject *>(bange::base::GetBaseFromProxy(1, vm));
	bange::sprite *sprite;
	sprite = new bange::sprite(layerobject->scenespace, vm);
	layerobject->AddObject(static_cast<bange::object *>(sprite));
	lua_pushvalue(vm, 1);
	int parent = luaL_ref(vm, LUA_REGISTRYINDEX);
	bange::BuildProxy(parent, static_cast<bange::base *>(sprite), vm);
	return 1;
}
